import service
import uix
import uiutil
import blue
import uthread
import xtriui
import log
import util
import types
import form
import uiconst
import uicls

class Form(service.Service):
    __guid__ = 'svc.form'
    __exportedcalls__ = {'GetForm': [],
     'ProcessForm': []}
    __servicename__ = 'form'
    __displayname__ = 'Form Service'
    __dependencies__ = []

    def __init__(self):
        service.Service.__init__(self)



    def GetForm(self, format, parent):
        (_form, retfields, reqresult, panels, errorcheck, refresh,) = self._GetForm(format, parent)
        _form.left = _form.width = const.defaultPadding
        if (_form.align == uix.UI_ALCLIENT):
            _form.width = _form.left
            _form.height = _form.top
        return (_form,
         retfields,
         reqresult,
         panels,
         errorcheck,
         refresh)



    def _GetForm(self, format, parent, retfields = [], reqresult = [], errorcheck = None, tabpanels = [], tabgroup = [], refresh = [], wipe = 1):
        if not uiutil.IsUnder(parent, eve.triapp.uilib.desktop):
            log.LogTraceback('Form parent MUST be hooked on the desktop; it is impossible to know the real dimensions of stuff within otherwise.')
        self.parent = parent
        self.retfields = retfields
        self.reqresult = reqresult
        self.errorcheck = errorcheck
        self.tabpanels = tabpanels
        self.tabgroup = tabgroup
        self.refresh = refresh
        FormWnd(self.parent)
        self.parent.sr.panels = {}
        self.parent.sr.focus = None
        if wipe:
            self.retfields = []
            self.reqresult = []
            self.tabpanels = []
            self.tabgroup = []
            self.refresh = []
        for each in format:
            self.type = each
            typeName = self.type['type']
            self.leftPush = (self.type.get('labelwidth', 0) or 80)
            self.code = None
            if (typeName == 'errorcheck'):
                self.AddErrorcheck()
                continue
            elif (typeName == 'data'):
                self.AddData()
                continue
            elif (typeName == 'tab'):
                self.AddTab()
                continue
            elif (typeName in ('btline', 'bbline')):
                self.AddLine()
                continue
            elif (typeName == 'push'):
                self.AddPush()
            elif (typeName == 'header'):
                self.AddHeader()
            elif (typeName == 'labeltext'):
                self.AddLabeltext()
            elif (typeName == 'text'):
                self.AddText()
            elif (typeName == 'edit'):
                self.AddEdit()
            elif (typeName == 'textedit'):
                self.AddTextedit()
            elif (typeName == 'checkbox'):
                self.AddCheckbox()
            elif (typeName == 'combo'):
                self.AddCombo()
            elif (typeName == 'btnonly'):
                self.AddBtnonly()
            else:
                uix.LogWarn('Unknown fieldtype in form generator')
                continue
            if self.type.has_key('key'):
                if self.code:
                    self.retfields.append([self.code, self.type])
                    self.parent.sr.Set(self.type['key'], self.code)
                else:
                    self.parent.sr.Set(self.type['key'], self.new)
            if (self.type.get('required', 0) == 1):
                self.reqresult.append([self.code, self.type])
            if ((self.type.get('selectall', 0) == 1) and getattr(self.code, 'SelectAll', None)):
                self.code.SelectAll()
            if (self.type.get('setfocus', 0) == 1):
                self.parent.sr.focus = self.code
            if (self.type.has_key('stopconfirm') and hasattr(self.code, 'stopconfirm')):
                self.code.stopconfirm = self.type['stopconfirm']
            if (self.type.get('frame', 0) == 1):
                idx = 0
                for child in self.new.children:
                    if child.name.startswith('Line'):
                        idx += 1

                uicls.Container(name='leftpush', parent=self.new, align=uiconst.TOLEFT, width=6, idx=idx)
                uicls.Container(name='rightpush', parent=self.new, align=uiconst.TORIGHT, width=6, idx=idx)
                uicls.Line(parent=self.new, align=uiconst.TOLEFT, idx=idx)
                uicls.Line(parent=self.new, align=uiconst.TORIGHT, idx=idx)

        if (wipe and len(self.tabgroup)):
            tabs = form.TabGroup(uicls.Container(name='tabparent', align=uiconst.TOTOP, width=0, height=18, parent=self.parent, idx=0)).Startup(self.tabgroup, 'hybrid')
            maxheight = 0
            for panel in self.tabpanels[:]:
                maxheight = max(maxheight, panel.height)

            self.parent.height = (maxheight + tabs.height)
        elif len(self.tabpanels):
            for each in self.tabpanels:
                each.state = uix.UI_HIDDEN

            self.tabpanels[0].state = uix.UI_PICKCHILDREN
        uix.RefreshHeight(self.parent)
        uicore.registry.SetFocus(self)
        return (self.parent,
         self.retfields,
         self.reqresult,
         self.tabpanels,
         self.errorcheck,
         self.refresh)



    def AddErrorcheck(self):
        self.errorcheck = self.type['errorcheck']



    def AddData(self):
        self.retfields.append(self.type['data'])



    def AddTab(self):
        (_form, _retfield, _required, _tabpanels, _errorcheck, _refresh,) = self._GetForm(self.type['format'], uicls.Container(name='form', align=uiconst.TOTOP, parent=self.parent), self.retfields, self.reqresult, self.errorcheck, self.tabpanels, self.tabgroup, self.refresh, 0)
        if self.type.has_key('key'):
            self.parent.sr.panels[self.type['key']] = _form
        if self.type.get('panelvisible', 0):
            _form.state = uix.UI_PICKCHILDREN
        else:
            _form.state = uix.UI_HIDDEN
        if self.type.has_key('tabvisible'):
            if (self.type['tabvisible'] == 1):
                self.tabgroup.append([self.type['tabtext'],
                 _form,
                 self,
                 None])
        else:
            self.tabgroup.append([self.type['tabtext'],
             _form,
             self,
             None])



    def AddPush(self):
        self.new = uicls.Container(name='push', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 6))



    def AddLine(self):
        uicls.Line(parent=self.parent, align=uiconst.TOTOP)



    def AddHeader(self):
        self.new = uicls.Container(name='headerField', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 17))
        header = uicls.Label(text=self.type.get('text', ''), parent=self.new, name='header', left=7, width=7, height=3, top=3, fontsize=9, letterspace=2, uppercase=1, linespace=9, align=uiconst.TOTOP, autoheight=True, state=uiconst.UI_NORMAL)
        self.new.height = int((header.height * 1.5))
        self.refresh.append((self.new, header))
        if not self.type.get('hideLine', False):
            uicls.Line(parent=self.new, align=uiconst.TOBOTTOM, idx=0)



    def AddLabeltext(self):
        self.new = uicls.Container(name='labeltextField', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 20))
        text = uicls.Label(text=self.type.get('text', ''), parent=self.new, align=uiconst.TOALL, name='text', left=self.leftPush, top=3, width=0, state=uiconst.UI_NORMAL, autowidth=False, autoheight=False)
        label = self.type.get('label', '')
        if (label and (label != '_hide')):
            label = uicls.Label(text=label, parent=self.new, name='label', left=7, width=(self.leftPush - 6), autowidth=False, top=5, fontsize=9, letterspace=2, uppercase=1, linespace=9)
            self.refresh.append((self.new,
             text,
             label))
        else:
            self.refresh.append((self.new, text))
        if (label == '_hide'):
            self.code.text = 0



    def AddText(self):
        left = self.type.get('left', 0)
        self.new = uicls.Container(name='textField', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 20), padding=(left,
         0,
         0,
         0))
        fontsize = self.type.get('fontsize', 12)
        if self.type.get('tabstops', []):
            text = uicls.Label(text=self.type.get('text', ''), parent=self.new, align=uiconst.TOTOP, name='text', left=0, top=3, tabs=self.type.get('tabstops', []), fontsize=fontsize, state=uiconst.UI_NORMAL)
        else:
            text = uicls.Label(text=self.type.get('text', ''), parent=self.new, align=uiconst.TOTOP, name='text', left=0, top=3, fontsize=fontsize, singleline=0, autowidth=False, state=uiconst.UI_NORMAL)
        self.new.height = max(self.new.height, int((text.textheight + 6)))
        self.refresh.append((self.new, text))



    def AddEdit(self):
        self.new = uicls.Container(name='editField', parent=self.parent, align=uiconst.TOTOP, height=20)
        w = self.type.get('width', -1)
        config = ('edit_%s' % self.type['key'])
        self.code = uicls.SinglelineEdit(name=config, parent=self.new, setvalue=self.type.get('setvalue', ''), left=(self.leftPush - 1), width=w, ints=self.type.get('intonly', None), floats=self.type.get('floatonly', None), align={False: uiconst.TOALL,
         True: uiconst.TOLEFT}[(w >= 0)], maxLength=(self.type.get('maxlength', None) or self.type.get('maxLength', None)), passwordCharacter=self.type.get('passwordChar', None), readonly=self.type.get('readonly', 0), autoselect=self.type.get('autoselect', 0))
        self.code.height = 2
        if self.type.has_key('OnReturn'):
            self.code.data = {'key': self.type['key']}
            self.code.OnReturn = self.type['OnReturn']
        if self.type.has_key('unusedkeydowncallback'):
            self.code.OnUnusedKeyDown = self.type['unusedkeydowncallback']
        if self.type.has_key('onanychar'):
            self.code.OnAnyChar = self.type['onanychar']
        label = self.type.get('label', '')
        text = self.type.get('text', None)
        caption = ''
        if (text is not None):
            caption = text
        else:
            caption = label
        if (label and (label != '_hide')):
            l = uicls.Label(text=caption, parent=self.new, name='label', left=7, width=(self.leftPush - 6), autowidth=False, top=5, fontsize=9, letterspace=2, uppercase=1, linespace=9)
            l.top = ((self.new.height - l.textheight) / 2)
        if (label == '_hide'):
            self.code.left = -3
            self.code.width -= 3
        if self.type.get('adjustWidth', False):
            self.code.width = max(self.code.width, l.textwidth)



    def AddTextedit(self):
        self.new = uicls.Container(name='texteditField', parent=self.parent, align=uiconst.TOTOP, top=0, left=0, height=self.type.get('height', 68))
        if self.type.get('readonly', 0):
            self.code = uix.GetTextedit((self.type.get('setvalue', '') or self.type.get('text', '')), self.new, left=(self.leftPush - 2), top=2, height=2, maxLength=(self.type.get('maxlength', None) or self.type.get('maxLength', None)), showAttribPanel=self.type.get('showAttribPanel', 0), readonly=self.type.get('readonly', 0), hideBackground=self.type.get('hideBackground', 0))
        else:
            self.code = uicls.EditPlainText(setvalue=(self.type.get('setvalue', '') or self.type.get('text', '')), parent=self.new, left=(self.leftPush - 2), top=2, height=2, showattributepanel=self.type.get('showAttribPanel', 0), maxLength=(self.type.get('maxlength', None) or self.type.get('maxLength', None)))
        label = self.type.get('label', '')
        if (label and (label != '_hide')):
            uicls.Label(text=label, parent=self.new, name='label', left=7, width=(self.leftPush - 6), autowidth=False, top=5, fontsize=9, letterspace=2, uppercase=1, linespace=9)
        if (label == '_hide'):
            self.code.left = -3
            self.code.width -= 3



    def AddCheckbox(self):
        self.new = uicls.Container(name='checkboxCont', parent=self.parent, align=uiconst.TOTOP, pos=(0, 0, 0, 18))
        self.code = uicls.Checkbox(text=self.type.get('text', ''), parent=self.new, configName='none', retval=self.type['key'], checked=self.type.get('setvalue', 0), groupname=self.type.get('group', None), callback=self.parent.OnCheckboxChange)
        self.code.data = {}
        onchange = (self.type.get('OnChange', None) or self.type.get('onchange', None))
        if onchange:
            self.code.data = {'key': self.type['key'],
             'callback': onchange}
        if self.type.has_key('showpanel'):
            self.code.data['showpanel'] = self.type['showpanel']
        if self.code.sr.label:
            self.refresh.append((self.code, self.code.sr.label))
        if self.type.get('hidden', 0):
            self.code.state = uix.UI_HIDDEN



    def AddCombo(self):
        self.new = uicls.Container(name='comboField', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 20))
        w = self.type.get('width', -1)
        options = self.type.get('options', [(mls.UI_GENERIC_NONE, None)])
        self.code = uicls.Combo(label='', parent=self.new, options=options, name=self.type.get('key', 'combo'), select=self.type.get('setvalue', ''), pos=(0, 2, 0, 0), width=w, align=[uiconst.TOLEFT, uiconst.TOALL][(w == -1)], callback=self.type.get('callback', None), labelleft=self.leftPush)
        label = self.type.get('label', '')
        if (label and (label != '_hide')):
            l = uicls.Label(text=label, parent=self.new, name='label', left=7, width=(self.leftPush - 6), autowidth=False, top=5, fontsize=9, letterspace=2, uppercase=1, linespace=9)
            l.top = ((self.new.height - l.textheight) / 2)
        if self.type.get('adjustWidth', False):
            self.code.width = max(self.code.width, l.textwidth)



    def AddBtnonly(self):
        self.new = uicls.Container(name='btnonly', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 20))
        btns = []
        align = uix.UI_ALRIGHT
        for wantedbtn in self.type['buttons']:
            if wantedbtn.has_key('align'):
                al = {'left': uix.UI_ALLEFT,
                 'right': uix.UI_ALRIGHT}
                align = al.get(wantedbtn['align'], uix.UI_ALRIGHT)

        btns.append([wantedbtn['caption'],
         wantedbtn['function'],
         wantedbtn.get('args', 'self'),
         None,
         wantedbtn.get('btn_modalresult', 0),
         wantedbtn.get('btn_default', 0),
         wantedbtn.get('btn_cancel', 0)])
        uicls.Container(name='push', parent=self.new, align=uiconst.TOTOP, height=4)
        btns = uix.MakeBtnGroup(btns, align=align, line=0, where=self.new, uniSize=self.type.get('uniSize', 1))
        btns.align = uix.UI_ALTOP



    def ProcessForm(self, retfields, required, errorcheck = None):
        result = {}
        for each in retfields:
            if (type(each) == dict):
                result.update(each)
                continue
            value = each[0].GetValue()
            if ((each[1]['type'] == 'checkbox') and (each[1].has_key('group') and (value == 1))):
                result[each[1]['group']] = each[1]['key']
            else:
                result[each[1]['key']] = value

        if errorcheck:
            hint = errorcheck(result)
            if (hint == 'silenterror'):
                return 
            if hint:
                eve.Message('CustomInfo', {'info': hint})
                return 
            if len(required):
                for each in required:
                    retval = each[0].GetValue()
                    if ((retval is None) or ((retval == '') or ((type(retval) in types.StringTypes) and (retval.strip() == '')))):
                        fieldname = ''
                        if each[1].has_key('label'):
                            fieldname = each[1]['label']
                            if (fieldname == '_hide'):
                                fieldname = each[1]['key']
                        else:
                            fieldname = each[1]['key']
                        eve.Message('MissingRequiredField', {'fieldname': fieldname})
                        return 
                    if ((each[1]['type'] == 'checkbox') and each[1].has_key('group')):
                        if (each[1]['group'] not in result):
                            eve.Message('MissingRequiredField', {'fieldname': each[1]['group']})
                            return 

            return result




class FormWnd(uicls.Container):
    __guid__ = 'xtriui.FormWnd'

    def _OnClose(self):
        uicls.Container._OnClose(self)
        windowKeys = self.sr.panels.keys()
        for key in windowKeys:
            if not self.sr.panels.has_key(key):
                continue
            wnd = self.sr.panels[key]
            del self.sr.panels[key]
            if ((wnd is not None) and (not wnd.destroyed)):
                wnd.Close()

        self.sr.panels = None



    def ShowPanel(self, panelkey):
        for key in self.sr.panels:
            self.sr.panels[key].state = uix.UI_HIDDEN

        self.sr.panels[panelkey].state = uix.UI_NORMAL



    def OnCheckboxChange(self, sender, *args):
        if sender.data.has_key('callback'):
            sender.data['callback'](sender)
        if (sender.data.has_key('showpanel') and self.sr.panels.has_key(sender.data['showpanel'])):
            self.ShowPanel(sender.data['showpanel'])



    def OnChange(self, *args):
        return 




